package com.example.project.utils;

import jakarta.annotation.Resource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * Redis 工具类，封装常用操作
 */
@Component
public class RedisUtil {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    // --------------------- 通用操作 ---------------------

    /**
     * 设置键值对的过期时间
     *
     * @param key     键
     * @param timeout 过期时间
     * @param unit    时间单位
     * @return 是否成功
     */
    public boolean expire(String key, long timeout, TimeUnit unit) {
        try {
            return redisTemplate.expire(key, timeout, unit);
        } catch (Exception e) {
            throw new RuntimeException("Redis expire failed: " + e.getMessage(), e);
        }
    }

    /**
     * 获取键的剩余过期时间
     *
     * @param key  键
     * @param unit 时间单位
     * @return 剩余时间（单位由 unit 指定），-1 表示永不过期，-2 表示键不存在
     */
    public long getExpire(String key, TimeUnit unit) {
        try {
            return redisTemplate.getExpire(key, unit);
        } catch (Exception e) {
            throw new RuntimeException("Redis getExpire failed: " + e.getMessage(), e);
        }
    }

    /**
     * 删除单个键
     *
     * @param key 键
     * @return 是否成功
     */
    public boolean delete(String key) {
        try {
            return redisTemplate.delete(key);
        } catch (Exception e) {
            throw new RuntimeException("Redis delete failed: " + e.getMessage(), e);
        }
    }

    /**
     * 批量删除键
     *
     * @param keys 键集合
     * @return 删除成功的数量
     */
    public long delete(Collection<String> keys) {
        try {
            return redisTemplate.delete(keys);
        } catch (Exception e) {
            throw new RuntimeException("Redis delete batch failed: " + e.getMessage(), e);
        }
    }

    /**
     * 检查键是否存在
     *
     * @param key 键
     * @return 是否存在
     */
    public boolean hasKey(String key) {
        try {
            return redisTemplate.hasKey(key);
        } catch (Exception e) {
            throw new RuntimeException("Redis hasKey failed: " + e.getMessage(), e);
        }
    }

    // --------------------- 字符串操作 ---------------------

    /**
     * 设置字符串值
     *
     * @param key   键
     * @param value 值
     */
    public void set(String key, String value) {
        try {
            stringRedisTemplate.opsForValue().set(key, value);
        } catch (Exception e) {
            throw new RuntimeException("Redis set failed: " + e.getMessage(), e);
        }
    }

    /**
     * 设置字符串值并指定过期时间
     *
     * @param key     键
     * @param value   值
     * @param timeout 过期时间
     * @param unit    时间单位
     */
    public void set(String key, String value, long timeout, TimeUnit unit) {
        try {
            stringRedisTemplate.opsForValue().set(key, value, timeout, unit);
        } catch (Exception e) {
            throw new RuntimeException("Redis set with timeout failed: " + e.getMessage(), e);
        }
    }

    /**
     * 获取字符串值
     *
     * @param key 键
     * @return 值
     */
    public String get(String key) {
        try {
            return stringRedisTemplate.opsForValue().get(key);
        } catch (Exception e) {
            throw new RuntimeException("Redis get failed: " + e.getMessage(), e);
        }
    }

    /**
     * 递增指定键的值
     *
     * @param key   键
     * @param delta 增量
     * @return 递增后的值
     */
    public long increment(String key, long delta) {
        try {
            return stringRedisTemplate.opsForValue().increment(key, delta);
        } catch (Exception e) {
            throw new RuntimeException("Redis increment failed: " + e.getMessage(), e);
        }
    }

    // --------------------- 哈希操作 ---------------------

    /**
     * 设置哈希值
     *
     * @param key   键
     * @param field 字段
     * @param value 值
     */
    public void hSet(String key, String field, Object value) {
        try {
            redisTemplate.opsForHash().put(key, field, value);
        } catch (Exception e) {
            throw new RuntimeException("Redis hSet failed: " + e.getMessage(), e);
        }
    }

    /**
     * 获取哈希值
     *
     * @param key   键
     * @param field 字段
     * @return 值
     */
    public Object hGet(String key, String field) {
        try {
            return redisTemplate.opsForHash().get(key, field);
        } catch (Exception e) {
            throw new RuntimeException("Redis hGet failed: " + e.getMessage(), e);
        }
    }

    /**
     * 获取哈希表所有字段和值
     *
     * @param key 键
     * @return 哈希表
     */
    public Map<Object, Object> hGetAll(String key) {
        try {
            return redisTemplate.opsForHash().entries(key);
        } catch (Exception e) {
            throw new RuntimeException("Redis hGetAll failed: " + e.getMessage(), e);
        }
    }

    /**
     * 删除哈希表中的字段
     *
     * @param key    键
     * @param fields 字段集合
     * @return 删除成功的数量
     */
    public long hDelete(String key, Object... fields) {
        try {
            return redisTemplate.opsForHash().delete(key, fields);
        } catch (Exception e) {
            throw new RuntimeException("Redis hDelete failed: " + e.getMessage(), e);
        }
    }

    // --------------------- 列表操作 ---------------------

    /**
     * 向列表右侧添加元素
     *
     * @param key   键
     * @param value 值
     * @return 列表长度
     */
    public long lPush(String key, String value) {
        try {
            return stringRedisTemplate.opsForList().rightPush(key, value);
        } catch (Exception e) {
            throw new RuntimeException("Redis lPush failed: " + e.getMessage(), e);
        }
    }

    /**
     * 从列表左侧弹出元素
     *
     * @param key 键
     * @return 弹出的值
     */
    public String lPop(String key) {
        try {
            return stringRedisTemplate.opsForList().leftPop(key);
        } catch (Exception e) {
            throw new RuntimeException("Redis lPop failed: " + e.getMessage(), e);
        }
    }

    /**
     * 获取列表范围内的元素
     *
     * @param key   键
     * @param start 开始索引
     * @param end   结束索引
     * @return 元素列表
     */
    public List<String> lRange(String key, long start, long end) {
        try {
            return stringRedisTemplate.opsForList().range(key, start, end);
        } catch (Exception e) {
            throw new RuntimeException("Redis lRange failed: " + e.getMessage(), e);
        }
    }

    // --------------------- 集合操作 ---------------------

    /**
     * 向集合添加元素
     *
     * @param key    键
     * @param values 值
     * @return 添加成功的数量
     */
    public long sAdd(String key, String... values) {
        try {
            return stringRedisTemplate.opsForSet().add(key, values);
        } catch (Exception e) {
            throw new RuntimeException("Redis sAdd failed: " + e.getMessage(), e);
        }
    }

    /**
     * 获取集合所有元素
     *
     * @param key 键
     * @return 集合
     */
    public Set<String> sMembers(String key) {
        try {
            return stringRedisTemplate.opsForSet().members(key);
        } catch (Exception e) {
            throw new RuntimeException("Redis sMembers failed: " + e.getMessage(), e);
        }
    }

    /**
     * 删除集合中的元素
     *
     * @param key    键
     * @param values 值
     * @return 删除成功的数量
     */
    public long sRemove(String key, Object... values) {
        try {
            return stringRedisTemplate.opsForSet().remove(key, values);
        } catch (Exception e) {
            throw new RuntimeException("Redis sRemove failed: " + e.getMessage(), e);
        }
    }
}